//
//  DBLexer.m
//  parser
//
//  Created by Daniel Braun on 04/05/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "DBLexer.h"
#import "DBRegex.h"

@interface NSString (LexerMatch)
- (int) matchStartOfString:(NSString *)s;
@end
@interface NSCharacterSet (LexerMatch)
- (int) matchStartOfString:(NSString *)s;
@end

@implementation NSString (LexerMatch)
- (int) matchStartOfString:(NSString *)s
{
	NSRange r=[s rangeOfString:self];
	if (r.length<=0) return 0;
	if (r.location>0) return 0;
	return r.length;
}	

@end

@implementation  NSCharacterSet (LexerMatch)
- (int) matchStartOfString:(NSString *)s
{
	NSRange r=[s rangeOfCharacterFromSet:self options:0];
	if (r.length<=0) return 0;
	if (r.location>0) return 0;
	return r.length;
	
}

@end


@interface _LexerTok : NSObject {
@public
	id tok;
	int val;
	NSString *astdef;
}
- (id) initWithTok:(id)t value:(int)v  ast:(NSString *)ast;
+ (id) _lexerTokWithTok:(id)t value:(int)v ast:(NSString *)ast;
+ (id) eofToken;
@end

@implementation _LexerTok
- (id) initWithTok:(id)t value:(int)v ast:(NSString *)ast
{
	self=[super init];
	if (self) {
		tok=[t retain];
		astdef=[ast retain];
		val=v;
	}
	return self;
}
- (void) dealloc {
	[tok release];
	[astdef release];
	[super dealloc];
}

+ (id) _lexerTokWithTok:(id)t value:(int)v ast:(NSString *)ast
{
	id s=[[[self class] alloc]initWithTok:t value:v ast:ast];
	return [s autorelease];
}

+ (id) eofToken
{
	return [self _lexerTokWithTok:nil value:-99 ast:nil];
}

@end

@implementation DBLexerTokenMatch 
- (void) dealloc {
	[matchString release];
	[super dealloc];
}


- (id) initWithTokDef:(_LexerTok *)t string:(NSString *)v
{
	self=[super init];
	if (self) {
		tokdef=[t retain];
		matchString=[v retain];
	}
	return self;
}

+ (id) tokmatchWithTokDef:(_LexerTok *)t string:(NSString *)v
{
	id s=[[[self class] alloc]initWithTokDef:t string:v];
	return [s autorelease];
}

+ (id) eofToken
{
	return [self tokmatchWithTokDef:[_LexerTok eofToken] string:@"<eof>"];
}

- (NSString *)matchString
{
	return matchString;
}
- (int) tokval
{
	return tokdef->val;
}
- (NSString *) astdef
{
	return tokdef->astdef;
}

- (BOOL) isEof
{
	return [self tokval]==-99;
}

- (NSString *) description
{
	return [NSString stringWithFormat:@"tok %d str <%@>", tokdef->val, matchString];
}
@end


@implementation DBLexer

- (void) dealloc {
	[buffer release];
	[tokens release];
	
	[super dealloc];
}


- (id) init {
	self = [super init];
	if (self != nil) {
		tokens=[[NSMutableArray arrayWithCapacity:100]retain];
	}
	return self;
}

- (void) addToken:(id)tokval value:(int)value ast:(NSString *)astdef
{
	if (![tokval respondsToSelector:@selector(matchStartOfString:)]) {
		NSLog(@"bad tokval\n");
		return;
	}
	_LexerTok *l=[_LexerTok _lexerTokWithTok:tokval value:value ast:astdef];
	[tokens addObject:l];
}

- (void) addToken:(id)tokval value:(int)v 
{
	[self addToken:tokval value:v ast:nil];
}
- (int) _nextToken:(_LexerTok **)ptok inString:(NSString *)str
{
	int maxlen=0;
	_LexerTok *bestTok=nil;
	unsigned int i, count = [tokens count];
	for (i = 0; i < count; i++) {
		_LexerTok * t = [tokens objectAtIndex:i];
		int l=[t->tok matchStartOfString:str];
		if (l>maxlen) {
			maxlen=l;
			bestTok=t;
		}
	}
	if (!maxlen) return 0;
	*ptok=bestTok;
	return maxlen;
}
- (NSArray *) parseString:(NSString *)str
{
	NSMutableArray *result=[NSMutableArray arrayWithCapacity:1000];
	for (;;) {
		_LexerTok *t=nil;
		int len;
		len=[self _nextToken:&t inString:str];
		if (len<=0) {
			NSLog(@"parse error\n");
			return nil;
		}
		if (t && (t->val>=0)) {
			DBLexerTokenMatch *m=[DBLexerTokenMatch tokmatchWithTokDef:t
								    string:[str substringToIndex:len]];
			[result addObject:m];
		}
		if (len>=[str length]) break;
		str=[str substringFromIndex:(len)];
	}
	return result;
}

@end
